
#include "USvgIconEngine.h"
#include "IconFileTools.h"
#include <QDebug>
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QtSvg/QSvgRenderer>
#include <QPixmapCache>
#include <QDataStream>
#include <QHash>
#include <QPair>

typedef QPair<QIcon::Mode, QIcon::State> MSKeyPair;

QList<QString> pcmCacheKeys;

namespace usvg
{
//    enum class Mode//自定义QIcon的枚举，增加一个未定义状态
//    {
//        Undefined = -1,
//        Normal = QIcon::Mode::Normal,
//        Disabled = QIcon::Mode::Disabled,
//        Active = QIcon::Mode::Active,
//        Selected = QIcon::Mode::Selected,
//    };
//    enum class State
//    {
//        Undefined = -1,
//        On = QIcon::State::On,
//        Off = QIcon::State::Off,
//    };

    struct MatchedEntry //考虑是否要用namespace包含所有代码
    {
        QString svgPath;
        QIcon::Mode mode;
        QIcon::State state;

        // 默认设置如此，比如一张svg传入没有指定mode，state，就是这种情况,
        // 因为QIcon接口关于mode，off有默认参数：
        // void addFile(const QString &fileName, const QSize &size = QSize(), Mode mode = Normal, State state = Off);
        MatchedEntry()
        {
           svgPath= QString();
           mode = QIcon::Normal;
           state = QIcon::Off;
        }

        void store(QString svgPath,QIcon::Mode mode,QIcon::State state)
        {
            this->svgPath = svgPath;
            this->mode = mode;
            this->state = state;
        }
    };

    QDebug operator<<(QDebug debug,const MatchedEntry& entry)
    {
        debug.nospace() << "MatchedEntry("
                        << "svgPath: " << entry.svgPath << ","
                        << "mode: " << entry.mode << ","
                        << "state: " << entry.state << ")";
        return debug.space();
    }
}


/*
 * =================================
 *  Private类
 *  USvgIconEnginePrivate
 * =================================
*/
class USvgIconEnginePrivate : public QSharedData
{
public:

    /*
     * 记录当前QIcon对象所对应的图标图片文件的路径
    */
//    QString const * baseSvgPtr;
    QString baseSvg;

    /*
        以下几个容器的意义——仅仅用于记录传入的图片信息，
        因为IconEngine类会在 pixmap、paint中使用 这些图片信息，而图片信息的传入接口又是 addFile、addPixmap
        所以，只能在addFile、addPixmap中，把信息存入容器
        待pixmap、paint中需要使用这些信息的时候，直接从容器中取
    */





    /**
     *  主缓存容器:
     *  直接使用QPixmapCache，不用定义容器
     *  QPixmapCache应用场景：
     *        是因为从同一 SVG 渲染生成的 pixmap 会根据目标尺寸而不同
     *        QPixmapCache 作为一个全局缓存，其目的是避免重复渲染相同尺寸的图标。
     *        对每种 size、mode、state 组合进行缓存，可以减少不必要的重新渲染，提高性能
     */


    /**
     *  次缓存容器: pixmapCache
     *  主要应对在用户层面使用 addPixmap()这种额外接口添加的QPixmap(用户可能对于svg，直接转化为QPixmap，调用QIcon::addPixmap，进行传入
     *  QIcon::addPixmap最终调用到IconEngine::addPixmap
     *  addPixmap仅有图片对象的参数 mode、state，因此key只能包含这2个因素
     *  key: 当前svg图片的 mode，state 转化成的int key
     *  value: 当前svg图片，以mode，state状态转化为的 QPixmap
     */
    QHash<int,QPixmap>* pixmapCache;


    /*
     *  辅助容器，缩放场景需要的容器，存储真实的svg文件（路径）
     *  key: SvgIconEntry合成的哈希值，用int表示
     *  value: 当前svg文件对应的绝对路径（传入可能是相对路径、资源路径）
     *  QIcon::Mode范围：0-3
     *  QIcon::State范围：0-1，根据取值范围拟定生成key的策略
     *
     *
     */
    QHash<int,QString>* svgCache;

    QHash<MSKeyPair,QPixmap>* svgSerializedPixmap;//用于序列化，key不能用hash生成key，因为不可逆，反序列化时无法解析出mode，state

    QHash<QString,QPixmap>* svgEndCache;//测试替代QPixmapCache

public:
    USvgIconEnginePrivate()
    {
        pixmapCache = new QHash<int,QPixmap>;
        svgCache = new QHash<int,QString>;
        svgSerializedPixmap = new QHash<MSKeyPair,QPixmap>;
//        baseSvgPtr = new QString();//初始化为空串
        baseSvg = QString();

        svgEndCache = new QHash<QString,QPixmap>();
    }
    ~USvgIconEnginePrivate()
    {
        svgCache->clear();//是否要先判空再处理
        pixmapCache->clear();
        svgSerializedPixmap->clear();

        svgEndCache->clear();

        //考虑QPixmapCache是否需要 clear？首先它确实能够自动clear，是基于LRU方式
        //QPixmapCache::clear();执行与否，关系到 QPixmapCache应该如何设置key


        delete svgCache;
        delete pixmapCache;
        delete svgSerializedPixmap;

//        delete baseSvgPtr;


//        baseSvgPtr = nullptr;
        svgCache = nullptr;
        pixmapCache = nullptr;
        svgSerializedPixmap = nullptr;

        baseSvg = QString();

        delete svgEndCache;
        svgEndCache = nullptr;
    }

public:
     //判断指定路径的svg是否是合法的
     bool isValidSvg(const QString& filepath);

     /**
      * 根据指定 mode，state匹配目标svg
      * return true: 容器中存在指定mode，state的图片
      * return false: 表示不存在，经过回退策略，返回最终用于"假匹配"的mode
      * retSvgPathPtr: 返回匹配结果对应的svg绝对地址
      * retModePtr: 返回匹配结果对应的mode
      */
//      bool svgMatch(QIcon::Mode mode, QIcon::State state,QString* retSvgPathPtr,QIcon::Mode* retModePtr,QIcon::State* retStatePtr);
      bool svgMatch(QIcon::Mode mode, QIcon::State state,usvg::MatchedEntry* entry);
      bool matched(QIcon::Mode mode,QIcon::State state);

     //按照指定size渲染一个svg并转化为QPixmap
     QPixmap renderSvgWithSize(QSvgRenderer* renderer,QIcon::Mode mode,QIcon::State state,const QSize& targetSize,usvg::MatchedEntry* entry);
     void fallback();

};
void  USvgIconEnginePrivate::fallback()
{

}
bool USvgIconEnginePrivate::matched(QIcon::Mode mode, QIcon::State state)
{
    return svgCache->contains(MSKey(mode,state));
}
bool USvgIconEnginePrivate::svgMatch(QIcon::Mode mode, QIcon::State state,usvg::MatchedEntry* entry)
{
    if(matched(mode,state))//对于当前mode，state，直接匹配成功
    {
        entry->store(svgCache->value(MSKey(mode,state)),mode,state);//数据存入MatchedEntry
        return true;
    }

    //匹配失败，执行回退策略
    //fallback();
    QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
    if (mode == QIcon::Disabled || mode == QIcon::Selected)//Disabled、Selected
    {
        QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
        if(matched(QIcon::Normal,state))//若回退的 Normal可以匹配成功，则直接返回 Normal
        {
            entry->store(svgCache->value(MSKey(QIcon::Normal,state)),QIcon::Normal,state);
            return false;
        }
        if(matched(QIcon::Active,state))//若回退的 Active 可以匹配成功，则直接返回 Active
        {
            entry->store(svgCache->value(MSKey(QIcon::Active,state)),QIcon::Active,state);
            return false;
        }

        if(matched(mode,oppositeState))//若以上不能匹配，尝试切换state
        {
            entry->store(svgCache->value(MSKey(mode,oppositeState)),mode,oppositeState);
            return false;
        }
        if(matched(QIcon::Normal,oppositeState))
        {
            entry->store(svgCache->value(MSKey(QIcon::Normal,oppositeState)),QIcon::Normal,oppositeState);
            return false;
        }
        if(matched(QIcon::Active,oppositeState))
        {
            entry->store(svgCache->value(MSKey(QIcon::Active,oppositeState)),QIcon::Active,oppositeState);
            return false;
        }
        if(matched(oppositeMode,state))//若以上不能匹配，再尝试切换mode
        {
            entry->store(svgCache->value(MSKey(oppositeMode,state)),oppositeMode,state);
            return false;
        }
        if(matched(oppositeMode,oppositeState))//尝试mode，state都切换
        {
            entry->store(svgCache->value(MSKey(oppositeMode,oppositeState)),oppositeMode,oppositeState);
            return false;
        }
    }
    else // Normal、Active
    {
        QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
        if(matched(oppositeMode, state))
        {
            entry->store(svgCache->value(MSKey(oppositeMode,state)),oppositeMode,state);
            return false;
        }
        if (matched(mode, oppositeState))
        {
            entry->store(svgCache->value(MSKey(mode,oppositeState)),mode,oppositeState);
            return false;
        }
        if (matched(oppositeMode, oppositeState))
        {
            entry->store(svgCache->value(MSKey(oppositeMode,oppositeState)),oppositeMode,oppositeState);
            return false;
        }
        if(matched(QIcon::Disabled, state))
        {
            entry->store(svgCache->value(MSKey(QIcon::Disabled, state)),QIcon::Disabled, state);
            return false;
        }
        if(matched(QIcon::Selected, state))
        {
            entry->store(svgCache->value(MSKey(QIcon::Selected, state)),QIcon::Selected, state);
            return false;
        }
        if(matched(QIcon::Disabled, oppositeState))
        {
            entry->store(svgCache->value(MSKey(QIcon::Disabled, oppositeState)),QIcon::Disabled, oppositeState);
            return false;
        }
        if(matched(QIcon::Selected, oppositeState))
        {
            entry->store(svgCache->value(MSKey(QIcon::Selected, oppositeState)),QIcon::Selected, oppositeState);
            return false;
        }
    }
    entry->store(svgCache->value(MSKey(QIcon::Normal, QIcon::Off)),QIcon::Normal, QIcon::Off);
    return false;
}

//参数都是：目标XXX
QPixmap USvgIconEnginePrivate::renderSvgWithSize(QSvgRenderer* renderer,QIcon::Mode mode,QIcon::State state,const QSize& targetSize,usvg::MatchedEntry* entry)
{
    if(!svgCache || !renderer)
    {
        return QPixmap();
    }

    //存储匹配结果的结构体(svgPath,mode,state)
//    usvg::MatchedEntry entry;
//    qDebug() << "匹配之前 MatchedEntry = " << entry;
    bool match = svgMatch(mode,state,entry);
//    qDebug() << "匹配之后 MatchedEntry = " << entry;


    // 有个问题应考虑：返回的数据 ，怎么返回？好像还是要定义一个指针

    //此时已经得到匹配的数据（即使匹配没有成功，也得到了回退的数据）
    //使用所获数据...进一步处理

    renderer->load(entry->svgPath);//这里逻辑是不是有问题？应该load 当前图片baseSvg吧？ -------不不，没有错，就是应该load这个 fallback得到的最终path---------------
    qDebug() << "............load , baseSvg = " << baseSvg;

    if(!renderer->isValid())
    {
        return QPixmap();
    }

    //至此，找到了指定mode，state对应的svg，并且renderer渲染器load成功

    /**
     * 处理需要的targetSize
     *      根据retSize大小构造目标Qpixmap
     *      不能直接用 targetSize，因为targetSize可能和原始svg宽高比不一样，强行设置size可能导致原始svg显示变形
     *      即最终retSize也不一定 == targetSize
     */
    QPixmap pixmp;
    QSize retSize = renderer->defaultSize();//获取renderer渲染的svg document的真实size
    retSize.scale(targetSize,Qt::KeepAspectRatio);//保持长宽比例放大
    if(retSize.isEmpty())//isEmpty(): width,height 任一<=0: true
    {
        return pixmp;
    }

    QImage tmpImg(retSize, QImage::Format_ARGB32_Premultiplied);//使用QImage转化为QPixmap
    tmpImg.fill(Qt::transparent);
    QPainter painter(&tmpImg);
    renderer->render(&painter);//将svg渲染到QPainter上

    pixmp = QPixmap::fromImage(tmpImg);
    return pixmp;
}
bool USvgIconEnginePrivate::isValidSvg(const QString& filepath)
{
    if(filepath.isEmpty() || (IconFileType::svg) != probeIconMimeType(filepath))//确保是svg类型的图片
    {
        return false;
    }
    QSvgRenderer tmpRender(filepath);
    return tmpRender.isValid();
}


/*
 * ======================
 * 主类
 * USvgIconEngine
 * ======================
*/
USvgIconEngine::~USvgIconEngine()
{
    qDebug() << "[ USvgIconEngine::~USvgIconEngine 析构 ]";
    if(d_ptr)
    {
        delete d_ptr;
    }
//    QPixmapCache::clear();//每个QIcon，单独配对一个QPixmapCache
}

USvgIconEngine::USvgIconEngine()
    :d_ptr(new USvgIconEnginePrivate)
{
    qDebug() << "[ USvgIconEngine::USvgIconEngine 构造, 初始d指针 ]";
}

//拷贝构造，深拷贝
USvgIconEngine::USvgIconEngine(const USvgIconEngine &other)
    :QIconEngine(other),d_ptr(new USvgIconEnginePrivate)
{
    qDebug() << "[ USvgIconEngine::USvgIconEngine 拷贝构造 ]";
    //d_ptr->pixmapCache = other.d_ptr->pixmapCache;
    //d_ptr->svgCache = other.d_ptr->svgCache;

    d_ptr->pixmapCache = new QHash<int,QPixmap>(*(other.d_ptr->pixmapCache));//深拷贝
    d_ptr->svgCache = new QHash<int,QString>(*(other.d_ptr->svgCache));
//    d_ptr->baseSvgPtr = new QString(*(other.d_ptr->baseSvgPtr));
    d_ptr->baseSvg = other.d_ptr->baseSvg;
    d_ptr->svgSerializedPixmap = new QHash<MSKeyPair,QPixmap>(*(other.d_ptr->svgSerializedPixmap));

}

/*
 * 由 QIcon::addFile() 调用.
 * 从文件中添加具有给定 fileName、size、mode、state 的 QPixmap;
 * 默认的基于QPixmap的IconEngine会存储提供的任何文件名，
 * 如果QPixmap的size与请求的图标size匹配，它会按需加载QPixmap，而不是使用缩放的像素图。
 * 实现svg格式的自定义IconEngine可以自由忽略任何额外的文件
*/
/**
 * addFile做2件事：
 * （1）用Hash容器svgCache 存储下来add的图片， [key:mode+state，value:绝对路径]————这考虑 一个QIcon对象，多次addFile的情况：（也就是规范地为不同状态，指定了多张相似的图）
 *      QIcon icon(":/svgs/resources/1.svg"); // 默认状态和模式是Normal, Off
        icon.addFile(":/svgs/resources/2.svg", QSize(), QIcon::Normal, QIcon::On); // 悬停状态
        icon.addFile(":/svgs/resources/3.svg", QSize(), QIcon::Active, QIcon::On); // 按下状态
    i   con.addFile(":/svgs/resources/4.svg", QSize(), QIcon::Disabled, QIcon::Off); // 禁用状态

 *  （2）用QString变量baseSvg记录下当前add的图片（的绝对路径）————针对当前QIcon对象，只添加一张图，即addFile只添加一次
 *  【可能用不上，主要用svgCache】
 *  【同一个QIcon对象多次addFile情况下，baseSvg可能没啥意义了】
 */
void USvgIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
{
    qDebug() << "[USvgIconEngine::addFile]";
    if(!d_ptr->isValidSvg(fileName))
    {
        qDebug() << "USvgIconEngine::addFile: 传入文件空路径为空字符串, 或者检测为非svg类型文件, 或svg document无效，总之，是非法的svg";
        return ;
    }
    //保证至此，传入svg document一定是valid
    //获取绝对路径，因为QiconEngine用于其他应用程序，其他应用程序可能使用其项目下的相对路径
    const QString absPath = getAbsPath(fileName);
    if(!absPath.isEmpty())
    {
        d_ptr->svgCache->insert(MSKey(mode,state),absPath);//若存在该key，则会覆盖的
        d_ptr->baseSvg = absPath;//这里要拷贝，否则absPath出作用域自动销毁而导致内容空
        qDebug() << "=====> addFile中初始化 d_ptr->baseSvg =" << d_ptr->baseSvg;
        qDebug() << "=====> addFile::svgCache->insert: [k:" << MSKey(mode,state) <<",v:"<<absPath <<"]";
    }
}

//用户层面，以pixmap形式传入icon
/*
 * 由 QIcon::addPixmap() 调用.
 * 默认的基于像素图的引擎存储任何提供的像素图，如果像素图的大小与请求的图标大小匹配，则它会使用它们而不是缩放的像素图。
 * 【这说明，需要一个容器来存储这个传入的pixmap】
 * 实现可缩放矢量格式的自定义图标引擎可以自由忽略任何额外的像素图。
*/
void USvgIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
{
    qDebug() << "[USvgIconEngine::addPixmap]";
    int key = MSKey(mode,state);
    d_ptr->pixmapCache->insert(key,pixmap);
}



/**
 * 将图标作为QPixmap返回，并具有所需的size、mode、size
 * 默认实现创建一个新的Qpixmap并调用 paint() 来填充它
 *
 * 需要处理svg
 *
 * QPixmapCache处理缓存：
 *      key(filepath,size,mode,state)
 *      value:QPixmap
 *  在QPixmapCache缓存中：
 *      若存在 key(filepath,size,mode,state)，则直接返回缓存的QPixmap，表明此前处理过该(filepath,size,mode,state)的图标对象
 *      若不存在 key(filepath,size,mode,state)，则需根据原始的svg，按照指定要求(filepath,size,mode,state)进行svg渲染，并转化为QPixmap 返回，并缓存QPixmapCache中
 */
//传入参数均为：目标XXX，目标大小，目标mode，state
QPixmap USvgIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
{

    /**
     * 是否应该首先 处理 像素比 问题？
     * 通过像素比，得到 真实的 targetSize
     *
     *
     * .......
     */


    qDebug() << "[USvgIconEngine::pixmap]";
    qDebug() << "USvgIconEngine::pixmap(): d_ptr->baseSvg = " << d_ptr->baseSvg;
    qDebug() << "USvgIconEngine::pixmap(): 所需返回的图片要满足 => size:" << size << ",mode:" << mode << ",state:" << state;


    if(d_ptr->baseSvg.isEmpty())//没有图片
    {
        qDebug() << "pixmap(): 没有图片，baseSvg = isEmpty()";
        return QPixmap();
    }

    //步骤二：检查次缓存容器
    if(d_ptr->pixmapCache)
    {
        qDebug() << "检查次缓存 pixmapCache...";
        QPixmap tmpix = d_ptr->pixmapCache->value(MSKey(mode,state));
        if(!tmpix.isNull() && tmpix.size() == size)//因为pixmapCache并没有存储size，所以需要额外判断
        {
            qDebug() << "pixmapCache 次缓存 命中, tmpix = " << tmpix;
            return tmpix;
        }
    }


    //步骤一：检查主缓存
    /**
     * 这里应该是要针对一个QIcon对象，N 次addFile进行处理的，传入路径可以，但是，你怎么找到当前 addFile图片的路径呢？
     * 总结：key只需要存储 size，mode，state
     * 因为当前 一个QIcon对象，不同mode，state addFile了不同图片，mode，state必然是不同的，则QPixmapCache根据mode，state来存储即可
     * size加入更好，不加也可，因为mode，state就能唯一标识一张svg
     *
     * 但是，因为你用的是QPixmapCache，QPixmapCache可能对应了多个QIcon对象，此时并不能根据mode，state来标识唯一一张图
     */
//

    bool match = d_ptr->matched(mode,state);//没有fallback的精准匹配
    if(match)//说明对于当前QIcon对象，用户确实通过addFile设置过一张mode，state的svg，则拿到对应svg Path后，检查QPixmapCache
    {
        qDebug() << "当前需求，mode+state match成功";
        //根据当前mode，state获取对应svg的path，看能否找到，但凡addFile了的，肯定能找到
        QString curSvgAbsPath = d_ptr->svgCache->value(MSKey(mode,state));

        const QString pcKey = pixmapCacheKey(curSvgAbsPath,size,mode,state);
        qDebug() << "pcKey = " << pcKey;

        qDebug() << "检查主缓存 QPixmapCache...";
        QPixmap tmpix;

        if(QPixmapCache::find(pcKey,&tmpix))
        {
            qDebug() << "QPixmapCache 主缓存命中 ,tmpix = " << tmpix;
            return tmpix;
        }
//        if(d_ptr->svgEndCache->contains(pcKey))
//        {
//            tmpix = d_ptr->svgEndCache->value(pcKey);
//            return tmpix;
//        }
    }
    else//用户根本没有设置一张基于所需mode，state的 svg图片
    {
        //pass ... fallback处理,就是下面程序
    }



    //此外，还有mode，state，size，像素比的问题
    //见下面 paint函数

    //根据mode、state渲染得到svg
    //基于该mode、state的svg可能不存在，因为QIcon QMode、QState是默认参数，若不指定，则默认为：Mode mode = Normal, State state = Off
    //这种情况下，用户传入的图片适用于mode=normal，state=off，而若需要显示其他mode，state的图片，则资源不存在

    //总结有2种特殊情况：
    //1、根本没有mode，state对应的图片，用svgCache验证
    //2、基于mode，state，有指定的图片，但图片是无效的svg，通过QSvgRenderer::load判断 QSvgRenderer render(filepath)构造默认调用load


    /**
     * 步骤三：检查svgCache
     * 因为需要的是QPixmap，上述步骤优先检查过 pixmapCache
     * 此时检查svgCache：
     *  if (match成功)：
     *      处理size
     *      得到pixmap，QPixmapCache将其缓存
     *      return pixmap
     *  else (match失败)：
     *      回退mode，state
     *      处理size
     *      得到pixmap，QPixmapCache将其缓存
     *      return pixmap
     */


    qDebug() << "主次缓存都没有命中，重新渲染、转pixmap";

    QPixmap pixmp;
    QSvgRenderer renderer;
    usvg::MatchedEntry entry;
    pixmp = d_ptr->renderSvgWithSize(&renderer,mode,state,size,&entry);


    const QString endKey = pixmapCacheKey(entry.svgPath,size,mode,state);

    QPixmapCache::insert(endKey,pixmp);//最终将该有效的pixmap缓存起来

//    d_ptr->svgEndCache->insert(endKey,pixmp);


    qDebug() << "QPixmapCache::insert: endKey =" << endKey << ",pixmp =" << pixmp;

    pcmCacheKeys.append(endKey);//测试用

    return pixmp;
}


/**
 * paint
 * 使用给定的 Painter 将具有指定mode、state的图标绘制到rect区域中
 * 要处理 设备像素比
 *
 *  Qt应用程序启用高 DPI 支持：
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
 */
void USvgIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
{
    qDebug() << "[USvgIconEngine::paint]";
    qreal dpr = 1.0;
    auto paintDevice = painter->device();
//    if (QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps))
//    {
//        dpr = paintDevice ? paintDevice->devicePixelRatioF() : qApp->devicePixelRatio();//获取绘制目标设备的设备像素比
//    }
    if(paintDevice)
    {
        dpr = paintDevice->devicePixelRatioF();
    }

    const QSize pixmapRealSize = rect.size() * dpr;
    QPixmap retPixmap = pixmap(pixmapRealSize,mode,state);

    painter->drawPixmap(rect,retPixmap);
}



/*
    返回 Engine 针对  所请求的大小、模式、状态，而提供的，实际的图标的size
    默认实现返回给定的大小。
*/
QSize USvgIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
{
    QPixmap pixmp = pixmap(size,mode,state);
    if(!pixmp.isNull())
    {
        return pixmp.size();
    }
    return QSize();
}




/*
    返回标识此IconEngine的key
*/
QString USvgIconEngine::key() const
{
    return QStringLiteral("USvgIconEngine");
}

QIconEngine* USvgIconEngine::clone() const
{
    return new USvgIconEngine(*this);
}
//反序列号：从流中读取数据
bool USvgIconEngine::read(QDataStream &in) {

    quint32 mpSize;
    in >> mpSize;
    for(auto i=0;i<mpSize;i++)
    {
        quint32 curMode,curState;
        in >> curMode >> curState;

        QImage image;
        in >> image;

        QPixmap pixmap = QPixmap::fromImage(image);
        //转换为原始的类型，存入map
        QIcon::Mode mode = static_cast<QIcon::Mode>(curMode);
        QIcon::State state = static_cast<QIcon::State>(curState);
        d_ptr->svgSerializedPixmap->insert(qMakePair(mode,state),pixmap);
    }
    return true;
}
//序列化：把数据写入流
bool USvgIconEngine::write(QDataStream &out) const {

    out << static_cast<quint32>(d_ptr->svgSerializedPixmap->size());//使用quint32固定类型的，适应于不同平台
    for(const auto& key:d_ptr->svgSerializedPixmap->keys()) //QHash<MSKeyPair,QPixmap>
    {
        const MSKeyPair& pair = key;
        const QPixmap& mp = d_ptr->svgSerializedPixmap->value(pair);

        out << static_cast<quint32>(pair.first) << static_cast<quint32>(pair.second);
        out << mp.toImage();//使用QImage，兼容性
    }
    return true;
}

void USvgIconEngine::virtual_hook(int id, void *data) {

}





void USvgIconEngine::printPixmapCache(const QHash<int, QPixmap>* pixmapCache) {
    if (!pixmapCache) {
        qDebug() << "pixmapCache is nullptr.";
        return;
    }

    if (pixmapCache->isEmpty()) {
        qDebug() << "pixmapCache is empty.";
        return;
    }

    qDebug() << "===============Printing pixmapCache contents===================";
    for (auto it = pixmapCache->begin(); it != pixmapCache->end(); ++it) {
        qDebug() << "Key:" << it.key()
                 << "Pixmap Size:" << it.value().size();
    }
    qDebug() <<"\n";
}

void USvgIconEngine::printSvgCache(const QHash<int, QString>* svgCache)
{
    if (!svgCache) {
        qDebug() << "svgCache is nullptr.";
        return;
    }

    if (svgCache->isEmpty()) {
        qDebug() << "svgCache is empty.";
        return;
    }

    qDebug() << "=============== svgCache  QHash<int, QString> ===============";
    qDebug() << "===svgCache.size = " << svgCache->size();
    for (auto it = svgCache->begin(); it != svgCache->end(); ++it) {
        qDebug() << "key  " << it.key()
                 << " , value  " << it.value();
        // 只打印前 50 个字符，避免过长
    }
    qDebug() <<  "============================================================\n";
}

const QHash<int,QString>* USvgIconEngine::getSvgCache() const
{
    return d_ptr->svgCache;
}


const QString USvgIconEngine::getBaseSvg() const
{
    return d_ptr->baseSvg;
}

void USvgIconEngine::printPcmCache()
{
    for(const auto& curKey:pcmCacheKeys)
    {
        QPixmap tmpPm;
        if(QPixmapCache::find(curKey,&tmpPm))
        {
            qDebug() << "[QPixmapCache key:" << curKey << "," << tmpPm << "]";
        }
    }
}
